package com.sg.file.common.util;

import com.sg.file.common.excption.NotDirectoryException;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件压缩工具类
 * Created by asus on 2018/8/10.
 */
@Slf4j
public class FileZip {
    /**
     * 文件打包
     * @param targetFilePath 被打包文件路径
     * @param zipFilePath 打包文件路径
     * @throws IOException
     */
    public static void zip(String targetFilePath,String zipFilePath) throws IOException {
        File zipFile = new File(zipFilePath);
        File targetFile = new File(targetFilePath);

        //如何压缩文件没有则创建
        if(!zipFile.exists()){
            zipFile.createNewFile();
        }
        //进行压缩
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));) {
            //如果是非目录文件，则直接进行文件打包
            if (!targetFile.isDirectory()) {
                toZipFile(zipOutputStream,null,targetFile);
                return;
            }
            try {
                //如果是目录文件，则需要进行文件目录打包
                toZipDirectory(zipOutputStream, targetFile.getName(), targetFile);
            }catch (NotDirectoryException e) {
                log.error("file is not directory！");
            }
        }

    }

    /**
     * 打包文件目录
     * @param zipOutputStream
     * @param fileDirectory
     */
    public static void toZipDirectory(ZipOutputStream zipOutputStream,
                                      String directoryName,
                                      File fileDirectory) throws NotDirectoryException {
        if(!fileDirectory.isDirectory()){
            throw new NotDirectoryException("this file is not Directory");
        }
        //将文件家夹中文件获取
        File[] files = fileDirectory.listFiles();
        //遍历文件夹中的所有文件，进行打包
        Arrays.asList(files).stream().forEach(file -> {
            StringBuilder fileNameSB = new StringBuilder(directoryName==null?"":directoryName)
                    .append(File.separator)
                    .append(file.getName());
            //如果是非目录文件，则将文件打包到压缩文件中
            if(!file.isDirectory()){
                //进行打包
                toZipFile(zipOutputStream,directoryName,file);
                return;
            }
            //如果文件夹中的文件依然是文件夹，则进行递归打包
            try {
                toZipDirectory(zipOutputStream,fileNameSB.toString(),file);
            } catch (NotDirectoryException e) {
                log.error("file is not directory！");
            }
        });
    }

    /**
     * 打包文件
     * @param zipOutputStream
     * @param directoryName 文件的上级目录名称
     * @param fileArrays
     */
    public static void toZipFile(ZipOutputStream zipOutputStream,
                                 String directoryName,
                                 File...fileArrays){
        //遍历需要打包的文件数组
        Arrays.asList(fileArrays).stream().forEach(file->{
            try (FileInputStream fileInputStream = new FileInputStream(file)) {
                StringBuilder fileNameSB = new StringBuilder(directoryName == null ? "" : directoryName)
                        .append(File.separator)
                        .append(file.getName());
                zipOutputStream.putNextEntry(new ZipEntry(fileNameSB.toString()));
                byte[] bytes = new byte[1024];
                int len = 0;
                while ((len = fileInputStream.read(bytes)) != -1) {
                    zipOutputStream.write(bytes, 0, len);
                }
            } catch (FileNotFoundException e) {
                log.error("file is not found in this path: {}",file.getPath());
            } catch (IOException e) {
                log.error("file IO exception: {}",e.getMessage());
            }
        });
    }

    /**
     * 打包文件
     * @param zipOutputStream
     * @param directoryName 文件的上级目录名称
     * @param filePathArrays
     */
    public static void toZipFile(ZipOutputStream zipOutputStream,
                                 String directoryName,
                                 String...filePathArrays){
        List<File> fileList = new ArrayList<>();
        for(String filePath:filePathArrays){
            File file = new File(filePath);
            fileList.add(file);
        }
        toZipFile(zipOutputStream,directoryName, (File[]) fileList.toArray());
    }

    /**
     * 打包文件
     * @param zipFile 压缩文件
     * @param directoryName 文件的上级目录名称
     * @param filePathArrays
     */
    public static void toZipFile(File zipFile,
                                 String directoryName,
                                 String...filePathArrays) throws IOException {
        try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile))) {
            toZipFile(zipOutputStream, directoryName, filePathArrays);
        }
    }
    /**
     * 打包文件
     * @param zipFilePath 压缩文件
     * @param directoryName 文件的上级目录名称
     * @param filePathArrays
     */
    public static void toZipFile(String zipFilePath,
                                 String directoryName,
                                 String...filePathArrays) throws IOException {
        File zipFile = new File(zipFilePath);
        //获取文件的父目录
        File parentFileDir = zipFile.getParentFile();
        //判断文件父目录是否创建
        if(!parentFileDir.exists()){
            parentFileDir.mkdirs();
        }
        //文件创建
        if(!zipFile.exists()){
            zipFile.createNewFile();
        }
        //进行文件压缩
        toZipFile(zipFile, directoryName, filePathArrays);
    }

}
